AWS Verified Access を使った時とパブリックALBを経由した場合のリクエスト情報を比較してみた
いわさです。
AWS Verified Access を使うと、プライベートネットワーク内で稼働する Web アプリケーションに外部からアクセス出来るようになるわけなのですが、よくあるパブリックサブネットの Application Load Balancer を経由する場合とリクエスト情報がどのように変わるのか気になりました。
Verified Access 経由した場合、アプリ側で気をつける点はあるのでしょうか。
結論としては CloudFront などを挟んだ場合と同じで、ALB から見たクライアント IP アドレスが Verified Access の ENI になったり、X-Forwarded-For が一段追加になるくらいで、あとは Verified Access 固有ヘッダーの x-amzn-ava-user-context が付与されるくらいでした。
検証結果をお知らせします。
検証環境作成
今回は次のように、サンプルアプリケーションをターゲットグループで指定するパブリックな Applcation Load Balancer とプライベートな Application Load Balancer を用意し、Verified Access からはプライベートな Application Load Balancer へアクセスさせたいと思います。信頼プロバイダーは Azure AD を使います。
それぞれの ALB のアクセスログを有効化して S3 へ出力します。
後ほどこのログを観察したいと思います。
また、EC2 からも Apache のアクセスログを CloudWatch Logs へ出力させて後ほど観察したいと思います。
上記一式(Verified Access と DNS と ACM 以外)を構築してくれる CloudFormation テンプレートを以下に作成しました。
こちらをデプロイすると Verified Access で必要なリソース情報を取得出来ます。
: Stack hoge0503app: UPDATE_COMPLETE Outputs: PrivateSubnetId1: subnet-00358c89cc7b80d73 VerifiedAccessSecurityGroup: sg-0b9fc57f7f7f9a026 PrivateLoadBalancerArn: arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/hoge0503app-internal-alb/5fabf2c7a1b5fbef PrivateSubnetId2: subnet-0750904da4dab1ca2
前回と同様に AWS CLI で作成しました。手順は記事のとおりなので割愛します。
また、デプロイ後にパブリックな ALB 用にも DNS レコードを作成します。何でも良いですけど私は Route 53 を使いました。
検証環境にアクセスする
今回は hoge0503public.tak1wa.com がパブリック経路、hoge0503private.tak1wa.com がプライベート(Verified Access)経路となります。
パブリック経路は次のように確認出来ました。
プライベート経路も Azure AD 認証が要求されます。
認証成功後、次のようにアプリケーションへアクセスすることが出来ました。
ログなどを確認してみる
ではアクセスが出来たので出力されたログを確認してみましょう。
その前に IP アドレスを抑えておきたいので ENI を確認します。
プライベート IP アドレスはこんな感じでした。
リソース | IPアドレス |
---|---|
EC2 | 10.0.2.137 |
Private ALB | 10.0.2.159, 10.0.3.175 |
Public ALB | 10.0.0.94, 10.0.1.216 |
Vertified Access ENI | 10.0.2.201, 10.0.3.238 |
私のパブリック IP | 203.0.113.1 |
※ パブリック IP アドレスはダミーに置き換えています
ALB アクセスログ
まず、次のように CloudFormation で作成された S3 バケットに出力されていることは確認出来ました。
S3 に出力したログなので Athena を使いましょう。
次の公式ドキュメントの手順に従うと必要なテーブルを用意してすぐに使用することが出来ます。
パブリック
まずはパブリック ALB のアクセスログです。
クライアント IP は直接の接続元 IP アドレスですね。
全てのヘッダーとか確認したかったのですが、ALB のアクセスログだとそこまでは確認出来ないようです。
余談ですが、アクセスログを確認してみるとデプロイして数分の間にboaform/admin/formLogin
など目掛けて外部からリクエストが送信されており、ひええーとなりました。
プライベート
プライベート ALB の場合は次のようにクライアント IP が Verified Access の ENI のプライベート IP になっていました。まぁそうだよなという感じです。
先程と比較すると全く攻撃を受けていないこともわかります。
他の情報はパブリックとあまり大差ないですね。
というか比較のための情報量が ALB のアクセスログだと少なすぎたかもしれないです。しまった。
CloudWatch Logs
EC2 の CloudWatch エージェントから CloudWatch Logs へ Apache のアクセスログを転送させているのでそちらも確認してみましょう。
次のようにインスタンス ID のロググループが作成されているはずです。
ただ、こちらもデフォルトのログフォーマットだったために情報量が少なかったです。しまった。
リクエストヘッダーを観察することに
アクセスログを見ても、接続元 IP アドレスが違うという点くらいしかわからなかったので、リクエスト情報を直接確認する作戦に切り替えました。
PHP あたりをインストールしてリクエストヘッダーを出力させます。
SSM セッションマネージャーで接続してインストールします。デフォルトのindex.html
は動的なものに置き換えます。
[ec2-user@ip-10-0-2-137 bin]$ sudo yum install php [ec2-user@ip-10-0-2-137 bin]$ sudo rm /var/www/html/index.html [ec2-user@ip-10-0-2-137 bin]$ sudo vi /var/www/html/index.php [ec2-user@ip-10-0-2-137 bin]$ sudo systemctl restart httpd.service
index.php
の内容は次を参考にさせて頂き、全ヘッダーを描画するようなものにしました。
パブリック
パブリック ALB の場合は次のようなリクエストヘッダーでした。
まぁ普通です。
X-Forwarded-For: 203.0.113.1 X-Forwarded-Proto: https X-Forwarded-Port: 443 Host: hoge0503public.tak1wa.com X-Amzn-Trace-Id: Root=1-645187e1-06c62a9a1ca0929d25a6d104 sec-ch-ua: "Chromium";v="112", "Google Chrome";v="112", "Not:A-Brand";v="99" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "macOS" upgrade-insecure-requests: 1 user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 sec-fetch-site: none sec-fetch-mode: navigate sec-fetch-user: ?1 sec-fetch-dest: document accept-encoding: gzip, deflate, br accept-language: en-US,en;q=0.9,ja;q=0.8 if-none-match: "5-5fabc1c1e6e1d" if-modified-since: Tue, 02 May 2023 20:51:56 GMT
プライベート
プライベート ALB の場合は次のようなリクエストヘッダーでした。
以下のハイライト部分が気になった点です。
それ以外はリソースの設定やブラウザの違いによるものなので Verified Access 云々は関係なさそうかなと思いました。
X-Forwarded-For: 203.0.113.1, 10.0.3.238 X-Forwarded-Proto: http X-Forwarded-Port: 80 Host: hoge0503private.tak1wa.com X-Amzn-Trace-Id: Self=1-64518862-15e322817b287acf7492b0ec;Root=1-64518862-0ba2121a29ff391b7306cd37 cache-control: max-age=0 sec-ch-ua: "Chromium";v="112", "Google Chrome";v="112", "Not:A-Brand";v="99" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "macOS" upgrade-insecure-requests: 1 user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 sec-fetch-site: none sec-fetch-mode: navigate sec-fetch-user: ?1 sec-fetch-dest: document accept-encoding: gzip, deflate, br accept-language: en-US,en;q=0.9 if-none-match: "5-5fabc1c1e6e1d" if-modified-since: Tue, 02 May 2023 20:51:56 GMT x-amzn-ava-user-context: eyJ0eXAiOiJKV1QiLCJraWQiOiJhODllZDQyZS0xYzg0LTRhOGYtODM1MS1kYTZkNTRjYmMyNzQiLCJhbGciOiJFUzM4NCIsImlzcyISAMPLEHBzOi8vbG9naW4ubWljcm9zb2Z0b25saW5lLmNvbS83MzBmMDI2Yi1mZTZjLTQ1YjQtYjAyMy1iMzBlYWMyNTcxODgvdjIuMCIsImNsaWVudCI6IjQxOTdmYTBkLTBiY2QtNDM5OC1iYWZkLTZhNjhlNjYxYmY5YyIsInNpZ25lciI6ImFybjphd3M6ZWMyOnVzLWVhc3QtMTo1NTA2Njk0SAMPLEg6dmVyaWZpZWQtYWNjZXNzLWluc3RhbmNlL3ZhaS0wODUzZDQzZmNhZjY4NzMzZCIsImV4cCI6MTY4MzA2NTA1MH0.eyJzdWIiOiJUYVZwV09fTkNyTHNsek5kQmhIMmpxeUdtSC1PWFVPb2hpQnRaak9RUFQ0IiwibmFtZSI6InVzZXIxaXdhc2SAMPLEYW1pbHlfbmFtZSI6IuOBu-OBkiIsImdpdmVuX25hbWUiOiLjgYTjgo_jgZUiLCJwaWN0dXJlIjoiaSAMPLE6Ly9ncmFwaC5taWNyb3NvZnQuY29tL3YxLjAvbWUvcGhvdG8vJHZhbHVlIiwiZW1haWwiOiJ1c2VyMUBhYWQudGFrMXdhLmNvbSIsImV4cCI6MTY4MzA2NTA1MCwiaXNzIjoiaHR0cHM6Ly9sb2dpbi5taWNyb3NvZnRvbmxpbmUuY29tLzczMGYwMjZiLWZlNmMtNDSAMPLEMDIzLWIzMGVhYzI1NzE4OC92Mi4wIn0.6bU1N0U5qLaJwHzRJG_4bngSAMPLEnixyKqPjbhxosfwNPL6GyxUw_6gAC9XyR71VLkelp26cDEwpwtq7M8F9g4KmFboDO-mJT9mCLbic725rNI9j8eQu6kl3qAY5d_l cookie:
X-Forwarded-For
ヘッダーは、直接 ALB へアクセスするクライアント である Verified Access の ENI と、エンドユーザーのパブリック IP アドレスで構成されています。
このあたりは CloudFront とか、ALB を多段にするとか、リバースプロキシを増やした場合と同じですね。
Host
ヘッダーは Verified Access のアプリケーションドメインが転送されていますね。
Verified Access から内部アプリケーションに HTTPS 通信させる際の SSL 証明書はどうする?と少し考えていたのですが、アプリケーションドメイン(今回だと hoge0503private.tak1wa.com)を使って問題無さそうだということが確認出来ました。
最も特徴的なのは、独自のx-amzn-ava-user-context
ヘッダーですね。
次の公式ドキュメントにも記述がありますが、ユーザークレームを含む JWT です。
jwt.io でデコードしてヘッダーとペイロードを確認してみます。
Azure AD から取得されたユーザー情報などが設定されています。
ただし、Azure AD の ID トークンと少し似ていますが、各クレームはよく確認するとちょっと違っていて、署名も Verified Access が独自で行ったものです。
IdP のトークンなどがそのまま転送されているわけではないということを覚えておきたいです。
さいごに
本日は AWS Verified Access を使った時とパブリックALBを経由した場合のリクエスト情報を比較してみました。
クライアント IP アドレスが Verified Access の ENI となるという点以外はリクエスト内容については概ね気にする点は無さそうという感想です。
CloudFront を前段に追加した場合と同じような考慮で Web アプリケーションは動作するのではないでしょうか。
加えてx-amzn-ava-user-context
で IdP 側の情報にも少しアクセス出来るよ、という感じですね。
個人的にはHost
ヘッダーが期待どおり転送されているのが確認出来て良かったです。Verifed Access の接続先の構成を考えるときの参考になりそうです。